import datetime
import json
from pathlib import Path
from flask import current_app, make_response


class BaseVO:
    dict_attrs = []   # 为了适配dict（）序列化, 选择哪些key需要被序列化
    model_map_vo = {
        # key: VOClass, 下方的VO有示例| 将指定的key的值，转换为对应的对象
    }
    # 需要URL编码的字段，例如：http://localhost/a/b c/ -> http://localhost/a/b%c/ 不会因为空格浏览器无法访问
    url_attrs = ['url', 'img', 'cw']

    def __init__(self, o_or_dict):
        self.__set_attr(o_or_dict)

    @staticmethod
    def __json_dumps_default_func(o):
        # if isinstance(o, list):  # 有些list不是常规的list
        #     return o
        if isinstance(o, BaseVO):
            return dict(o)
        if hasattr(o, '__dict__'):  # 应该判断属性是否存在
            return o.__dict__
        if isinstance(o, datetime.datetime):
            return o.isoformat().split('T')
        if isinstance(o, Path):  # path库的路径解包
            return str(o)
        return o
        # tp = str(type(o))
        # if tp.find('float') != -1:  # 兼容numpy类型
        #     return float(o)
        # if tp.find('array') != -1:  # 兼容numpy类型
        #     return o.tolist()
        # else:
        #     return o.__dict__

    def __json_dumps_self(self) -> str:
        # @NOTE 这里脱去外壳，将不能发挥重写的 __getitem__的作用
        # if len(self.dict_attrs) == 1 and isinstance(getattr(self, self.dict_attrs[0]), list):
        #     return json.dumps(getattr(self, self.dict_attrs[0]), default=self.__json_dumps_default_func)
        # dump前url进行编码
        return json.dumps(self, default=self.__json_dumps_default_func)

    def response(self):
        response = make_response()
        response.status_code = 200
        response.headers['Content-Type'] = 'application/json'
        response.data = self.__json_dumps_self()

        # @MODIFYED: 将只有单属性，值为序列进行转换 {"chapters": []} -> []
        if len(self.dict_attrs) == 1 and isinstance(getattr(self, self.dict_attrs[0]), list):
            response.data = json.dumps(json.loads(
                response.data)[self.dict_attrs[0]])
        response.headers['Access-Control-Allow-Origin'] = current_app.config['ACCESS_CONTROL_ALLOW_ORIGIN']
        return response

    def __set_attr(self, o_or_dict):
        # model中的有些内容是需要懒加载的，如果model.__dict__会直接加载，从而失效

        if len(self.dict_attrs) == 0:  # 全部返回可以不指定
            if not isinstance(o_or_dict, dict):
                o_or_dict = o_or_dict.__dict__
            for k, v in o_or_dict.items():
                setattr(self, k, v)
        else:
            for k in self.dict_attrs:  # 对象.__dict__ 并不会包含非属性的内容
                if hasattr(o_or_dict, k):
                    setattr(self, k, getattr(o_or_dict, k))
            # raise RuntimeError('传入的model不属于BaseModel！')

    def keys(self):  # 为了适配dict（）序列化
        return self.dict_attrs or self.__dict__.keys()  # 不设置默认所有属性全返回

    def __getitem__(self, key):
        item = getattr(self, key)
        # @NOTE
        if item is None:
            return item
        if key in self.model_map_vo.keys():
            if isinstance(item, list):
                return [self.model_map_vo[key](model) for model in item]
            else:
                return self.model_map_vo[key](item)
            # 为了适配dict（）序列化
        return item


class FailVideoVO(BaseVO):
    name: str
    dir: str


class FailChapterVO(BaseVO):
    name: str
    dir: str
    belong_course: str
    fail_videos: list[FailVideoVO]
    model_map_vo = {
        'fail_videos': FailVideoVO
    }


class FailCourseVO(BaseVO):
    name: str
    dir: str
    fail_chapters: list[FailChapterVO]
    model_map_vo = {
        'fail_chapters': FailChapterVO
    }


class ConfigVO(BaseVO):
    dict_attrs = ['step', 'speed']
